﻿using System;
using System.Collections.Generic;
using System.Reflection;
using UtilZ.Dotnet.Ex.Base;

namespace UtilZ.Dotnet.Ex.Json
{
    /// <summary>
    /// json节点
    /// </summary>
    public class JsonNode
    {
        private readonly Type _keyType;
        /// <summary>
        /// 字典集合key类型
        /// </summary>
        public Type KeyType
        {
            get { return _keyType; }
        }


        private readonly Type _type;
        /// <summary>
        /// 属性或字段成员值类型
        /// </summary>
        public Type Type
        {
            get
            {
                return _type;
            }
        }

        private readonly TypeCategorys _typeCategory;
        /// <summary>
        /// 类型分组
        /// </summary>
        public TypeCategorys TypeCategory
        {
            get { return _typeCategory; }
        }

        private JsonNodeCollection _children = null;
        /// <summary>
        /// 当前类型包包含的子类型集合
        /// </summary>
        public JsonNodeCollection Children
        {
            get { return _children; }
        }

        private readonly IJsonValueConverter _valueConverter = null;
        /// <summary>
        /// 序列化时值转换器
        /// </summary>
        public IJsonValueConverter ValueConverter
        {
            get { return _valueConverter; }
        }

        private readonly IJsonMemberIgnoreer _memberIgnoreer = null;
        /// <summary>
        /// 成员忽略器
        /// </summary>
        public IJsonMemberIgnoreer MemberIgnoreer
        {
            get { return _memberIgnoreer; }
        }


        private readonly MemberInfo _objectMemberInfo;
        /// <summary>
        /// 对象成员信息
        /// </summary>
        public MemberInfo ObjectMemberInfo
        {
            get
            {
                return this._objectMemberInfo;
            }
        }


        private readonly string _jsonMemberName;
        /// <summary>
        /// json成员名称
        /// </summary>
        public string JsonMemberName
        {
            get { return _jsonMemberName; }
        }

        private readonly int _order = -1;
        /// <summary>
        /// 序列化顺序
        /// </summary>
        public int Order
        {
            get { return _order; }
        }

        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; private set; } = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="objectMemberName"></param>
        /// <param name="useCamelCasePropertyNames">是否使用序列化后首字母小写,true:首字母小写;false:首字母不小写</param>
        /// <returns></returns>
        private string GetJsonMemberName(string objectMemberName, bool useCamelCasePropertyNames)
        {
            if (useCamelCasePropertyNames)
            {
                if (objectMemberName[0] >= 'A' && objectMemberName[0] <= 'Z')
                {
                    //因为 'a' - 'A' = 32 .所以首字母转小写,则为首字母+32即可
                    objectMemberName = ((char)(objectMemberName[0] + 32)) + objectMemberName.Substring(1);
                }
            }

            return objectMemberName;
        }

        /// <summary>
        /// 构造函数-属性和字段
        /// </summary>
        /// <param name="attribute">成员特性</param>
        /// <param name="memberInfo">对象成员信息</param>
        /// <param name="memberType">成员类型</param>
        /// <param name="memberTypeCategory">成员类型分组</param>
        /// <param name="useCamelCasePropertyNames">是否使用序列化后首字母小写,true:首字母小写;false:首字母不小写</param>
        public JsonNode(JsonPropertyAttribute attribute, MemberInfo memberInfo, Type memberType, TypeCategorys memberTypeCategory, bool useCamelCasePropertyNames)
        {
            this._order = attribute.Order;
            this._objectMemberInfo = memberInfo;
            this.Description = attribute.Description;

            this._type = memberType;

            Type type = Nullable.GetUnderlyingType(memberType);
            if (type == null)
            {
                type = memberType;
            }

            this._typeCategory = memberTypeCategory;

            if (attribute.ValueConverterType == null)
            {
                if (this._typeCategory == TypeCategorys.Basic || this._typeCategory == TypeCategorys.Any)
                {
                    this._valueConverter = JsonConverterManger.GetDefaultConverter(type);
                }
            }
            else
            {
                this._valueConverter = ActivatorEx.CreateInstance<IJsonValueConverter>(attribute.ValueConverterType);
            }

            if (attribute.MemberIgnoreerType != null)
            {
                this._memberIgnoreer = (IJsonMemberIgnoreer)Activator.CreateInstance(attribute.MemberIgnoreerType);
            }

            if (string.IsNullOrWhiteSpace(attribute.MemberName))
            {
                this._jsonMemberName = this.GetJsonMemberName(memberInfo.Name, useCamelCasePropertyNames);
            }
            else
            {
                this._jsonMemberName = attribute.MemberName;
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="typeCategorys"></param>
        /// <param name="converter"></param>
        public JsonNode(Type type, TypeCategorys typeCategorys, IJsonValueConverter converter)
        {
            this._type = type;
            this._typeCategory = typeCategorys;
            this._valueConverter = converter;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyType"></param>
        /// <param name="valueType"></param>
        /// <param name="typeCategorys"></param>
        /// <param name="converter"></param>
        public JsonNode(Type keyType, Type valueType, TypeCategorys typeCategorys, IJsonValueConverter converter)
        {
            this._keyType = keyType;
            this._type = valueType;
            this._typeCategory = typeCategorys;
            this._valueConverter = converter;
        }





        /// <summary>
        /// 更新子节点集合
        /// </summary>
        /// <param name="nodes"></param>
        public void UpdateChildren(JsonNodeCollection nodes)
        {
            if (nodes == null || nodes.Count == 0)
            {
                return;
            }

            this._children = nodes;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Sort()
        {
            if (this._children == null)
            {
                return;
            }
            List<JsonNodeCollection> list = new List<JsonNodeCollection>();
            this.Sort(this, list);
        }

        private void Sort(JsonNode jsonNode, List<JsonNodeCollection> list)
        {
            foreach (var node in jsonNode._children)
            {
                if (node._children == null || list.Contains(node._children))
                {
                    continue;
                }

                node._children.Sort();
                list.Add(node._children);
                this.Sort(node, list);
            }
        }





        /// <summary>
        /// 获取属性或字段值
        /// </summary>
        /// <param name="obj">属性或字段所属对象</param>
        /// <returns>属性或字段值</returns>
        public object GetValue(object obj)
        {
            object value;
            if (this._objectMemberInfo.MemberType == MemberTypes.Property)
            {
                value = ((PropertyInfo)this._objectMemberInfo).GetValue(obj, null);
            }
            else if (this._objectMemberInfo.MemberType == MemberTypes.Field)
            {
                value = ((FieldInfo)this._objectMemberInfo).GetValue(obj);
            }
            else
            {
                throw new ApplicationException(this._objectMemberInfo.MemberType.ToString());
            }

            return value;
        }


        /// <summary>
        /// 设置属性或字段值
        /// </summary>
        /// <param name="obj">属性或字段所属对象</param>
        /// <param name="jsonValue">json值</param>
        public void SetJsonValue(ref object obj, string jsonValue)
        {
            object value;
            if (this._valueConverter != null)
            {
                if (!this._valueConverter.TryConvertFrom(this._objectMemberInfo, this._type, obj, jsonValue, out value))
                {
                    throw new ArgumentException($"json值\"{jsonValue}\"转换为类型\"{this._type.FullName}\"失败");
                }
            }
            else
            {
                value = Convert.ChangeType(jsonValue, this._type);
            }

            this.SetValue(ref obj, value);
        }

        /// <summary>
        /// 设置属性或字段值
        /// </summary>
        /// <param name="obj">属性或字段所属对象</param>
        /// <param name="value">json值</param>
        public void SetValue(ref object obj, object value)
        {
            if (this._objectMemberInfo.MemberType == MemberTypes.Property)
            {
                PropertyInfo proInfo = (PropertyInfo)this._objectMemberInfo;
                if (!proInfo.CanWrite)
                {
                    return;
                }

                proInfo.SetValue(obj, value, null);
            }
            else if (this._objectMemberInfo.MemberType == MemberTypes.Field)
            {
                FieldInfo fieldInfo = (FieldInfo)this._objectMemberInfo;
                if (fieldInfo.IsInitOnly)
                {
                    return;
                }

                fieldInfo.SetValue(obj, value);
            }
            else
            {
                throw new ApplicationException(this._objectMemberInfo.MemberType.ToString());
            }
        }






        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            string memberName = this._objectMemberInfo == null ? null : this._objectMemberInfo.Name;
            return $"{memberName} {this._typeCategory.ToString()} {this.Type.FullName}";
        }
    }


}
